//
// Created by wxd on 2025/7/25.
//

#pragma once

#include <iostream>
#include <vector>
#include <glm/glm.hpp>
#include <glm/trigonometric.hpp>
#include "../wrapper/log/Logger.h"
#include "../wrapper/monitor/GLDebug.hpp"
#include "../global/ChineseOutput.hpp"
#include "../global/EngineDataProperties.h"
#include "../application/app/Application.h"
#include "../glFramework/shader/Shader.h"
#include "../glFramework/constant/engine_layout.h"
#include "../glFramework/texture/Texture.h"
#include "../glFramework/utils/ResourceLoadUtils.h"
#include "../glFramework/bo/VBO.h"
#include "../glFramework/bo/VAO.h"
#include "../glFramework/constant/engine_uniform.h"
#include <memory>

#include "bo/EBO.h"
#include "../global/output.hpp"

struct Perspective {
    float fov = 0.f;
    float aspect = 0.f;
    float zNear = 0.f;
    float zFar = 0.f;
};

struct FrameManager {
    float lastFrame = 0.f;
    float currFrame = 0.f;
    float deltFrame = 0.f;
};

struct Camera {
    glm::vec3 center = glm::vec3(0.f, 0.f, 1.f);
    glm::vec3 target = glm::vec3(0.f, 0.f, 0.f);
    glm::vec3 up = glm::vec3(0.f, 1.f, 0.f);
};

struct MvpManager {
    glm::mat4 model = glm::mat4(1.0f);
    glm::mat4 view = glm::mat4(1.0f);
    glm::mat4 proj = glm::mat4(1.0f);
};

struct RotateParams {
    float radius = 3.0f;
    float angleSpeed = 20.0f;
    float accAngle= 0.f;


    void updateAccAngle(float deltFrame) {
        if (deltFrame > 0.f) {
            accAngle += angleSpeed * deltFrame;
        }
    }

    void updatePeriod() {
        if (accAngle > 360.f) {
            accAngle -= 360.0f;
        }
    }
};

namespace Resource {
    inline const char* vertexPath = "../demo/shader/_011/vertex_shader.glsl";
    inline const char* fragmentPath = "../demo/shader/_011/fragment_shader.glsl";
    inline const char* texPath = "../demo/texture/earth.png";
}

inline Perspective mPerspective;;
inline FrameManager mFrameManager;
inline MvpManager mMvpManager;
inline Camera mCamera;
inline RotateParams rotParams;

#ifndef MY_CREATE_VIEW_MATRIX
#define MY_CREATE_VIEW_MATRIX
glm::mat4 lookAt(glm::vec3 eye, glm::vec3 target, glm::vec3 up) {
    glm::vec3 Front = glm::normalize(target - eye);
    glm::vec3 Right = glm::normalize(glm::cross(Front, up));
    glm::vec3 Up = glm::normalize(glm::cross(Right, Front));

    // 旋转相机，将相机旋转到与{(1,0,0), (0,1,0), (0,0,-1)}方向重叠， rot^- = {Right, Up, Front} -> rot^T = {Right, Up, Front}
    glm::mat4 rot = glm::mat4(0.f);
    rot[0] = glm::vec4(Right, 0.f);
    rot[1] = glm::vec4(Up, 0.f);
    rot[2] = glm::vec4(-Front, 0.f);
    rot[3] = glm::vec4(0.f, 0.f, 0.f, 1.f);

    // 移动相机，将相机移动到世界坐标系下的原点
    glm::mat4 trans = glm::mat4(1.f);
    trans[3] = glm::vec4(-eye, 1.f);

    // return trans * rot; // TODO：旋转的时候会有问题
    return glm::lookAt(eye, target, up);
}
#endif

#ifndef MY_CREATE_PROJECT_MATRIX
#define MY_CREATE_PROJECT_MATRIX
glm::mat4 perspective(float fov, float aspect, float zNear, float zFar) {
    // 确保参数有效
    assert(aspect != 0.0f);
    assert(zFar != zNear);

    // 计算焦距（focal length）
    float tanHalfFov = tan(fov / 2.0f);

    glm::mat4 mat(0.0f); // 初始化为全零矩阵

    // 透视投影矩阵的计算
    mat[0][0] = 1.0f / (aspect * tanHalfFov); // 缩放 x 坐标
    mat[1][1] = 1.0f / tanHalfFov;            // 缩放 y 坐标
    mat[2][2] = -(zFar + zNear) / (zFar - zNear); // 映射 z 坐标到 [-1, 1]
    mat[2][3] = -1.0f;                         // 设置 w 分量为 -z（用于透视除法）
    mat[3][2] = -(2.0f * zFar * zNear) / (zFar - zNear); // 深度映射

    return mat;
}
#endif

inline void onResize(int w, int h) {
    glViewport(0, 0, w, h);
}

inline void onKeyBoard(int key, int action, int mods) {
    if (key == GLFW_KEY_ESCAPE) {
        glfwSetWindowShouldClose(EngineApp.getCurrentWindow(), true);
    }
}

inline void initParams() {
    mPerspective.fov = glm::radians(45.f);
    mPerspective.aspect = EngineApp.getWindowAspectRatio();
    mPerspective.zNear = 0.1f;
    mPerspective.zFar = 100.f;

    mCamera.center = glm::vec3(0.0f, 0.0f, 3.0f);

    mMvpManager.view = lookAt(mCamera.center, mCamera.target, mCamera.up);
    mMvpManager.proj = perspective(mPerspective.fov, mPerspective.aspect, mPerspective.zNear, mPerspective.zFar);
}

inline void updateFrame() {
    mFrameManager.currFrame = static_cast<float>(glfwGetTime());
    if (mFrameManager.lastFrame > 0.f) {
        mFrameManager.deltFrame = mFrameManager.currFrame - mFrameManager.lastFrame;
    }
    mFrameManager.lastFrame = mFrameManager.currFrame;

    rotParams.updateAccAngle(mFrameManager.deltFrame);
    rotParams.updatePeriod();
}

inline void updateCamera() {
    float x = rotParams.radius * glm::sin(glm::radians(rotParams.accAngle));
    float z = rotParams.radius * glm::cos(glm::radians(rotParams.accAngle));
    mCamera.center.x = x;
    mCamera.center.z = z;
    std::cout << mCamera.center.x << "x: " << mCamera.center.y << "y: " << mCamera.center.z << "z: " << mCamera.center.z << std::endl;
    mMvpManager.view = lookAt(mCamera.center, mCamera.target, mCamera.up);
}

inline void render() {
ChineseOutput::init();
    EngineApp.initDefaultWindowConfig();
    EngineApp.setResizeCallback(onResize);
    EngineApp.setKeyBoardCallback(onKeyBoard);
    EngineApp.init();

    std::vector<float> vertices;
    vertices.reserve(32); // 顶点坐标 + 颜色 + 纹理坐标
    std::vector<unsigned int> indices;
    indices.reserve(6);

    vertices.push_back(0.5f);
    vertices.push_back(0.5f);
    vertices.push_back(0.0f);
    vertices.push_back(1.0f);
    vertices.push_back(0.0f);
    vertices.push_back(0.0f);
    vertices.push_back(1.0f);
    vertices.push_back(1.0f);
    vertices.push_back(0.5f);
    vertices.push_back(-0.5f);
    vertices.push_back(0.0f);
    vertices.push_back(0.0f);
    vertices.push_back(1.0f);
    vertices.push_back(0.0f);
    vertices.push_back(1.0f);
    vertices.push_back(0.0f);
    vertices.push_back(-0.5f);
    vertices.push_back(-0.5f);
    vertices.push_back(0.0f);
    vertices.push_back(0.0f);
    vertices.push_back(0.0f);
    vertices.push_back(1.0f);
    vertices.push_back(0.0f);
    vertices.push_back(0.0f);
    vertices.push_back(-0.5f);
    vertices.push_back(0.5f);
    vertices.push_back(0.0f);
    vertices.push_back(1.0f);
    vertices.push_back(0.0f);
    vertices.push_back(0.0f);
    vertices.push_back(0.0f);
    vertices.push_back(1.0f);

    indices.push_back(0);
    indices.push_back(1);
    indices.push_back(2);
    indices.push_back(0);
    indices.push_back(2);
    indices.push_back(3);

    Texture texture(Resource::texPath);
    texture.setSamplerName(EngineUniform::uTexUnit);

    VAO vao;
    vao.bind();
    VBO vbo(vertices);
    EBO ebo(indices);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, fSize(8), reinterpret_cast<void *>(0));
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, fSize(8), reinterpret_cast<void *>(3 * sizeof(float)));
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, fSize(8), reinterpret_cast<void *>(6 * sizeof(float)));
    glEnableVertexAttribArray(2);
    vao.unbind();

    std::unique_ptr<Shader> shader = std::make_unique<Shader>(Resource::vertexPath, Resource::fragmentPath);

    initParams();

    while (EngineApp.update()) {
        glClear(GL_COLOR_BUFFER_BIT);

        updateFrame();
        updateCamera();

        shader->bindProgram();
        shader->setUniform("uModel", mMvpManager.model);
        shader->setUniform("uView", mMvpManager.view);
        shader->setUniform("uProj", mMvpManager.proj);
        shader->setUniform(texture.getSamplerName(), texture.getTextureUnit()); // 采样0号单元
        vao.bind();
        GL_CALL(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, reinterpret_cast<void*>(0)))
        vao.unbind();
        shader->unbindProgram();
    }

    vao.destroy();
    vbo.destroy();
    ebo.destroy();
    shader->deleteProgram();
    EngineApp.destroy();
}
